﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Net.Sockets;
using System.Net;
using System.Text;
using System.IO;
using System.Text.RegularExpressions;
using System.Configuration;

namespace FredBot
{
    public class LogReceiver
    {
#if DEBUG
        private const int listenPort = 27500;
#else
        private const int listenPort = 27510;
#endif

        public static void Parse()
        {
            bool done = false;
            UdpClient listener = new UdpClient(listenPort);
            IPEndPoint groupEP = new IPEndPoint(IPAddress.Any, listenPort);
            string received_data;
            byte[] receive_byte_array;
            string dateFormat = "MM/dd/yyyy - HH:mm:ss";
            DateTime parsedDate;
            Dictionary<String, LogLineParser> parsers = new Dictionary<string, LogLineParser>();
            TFDataEntities context = new TFDataEntities();
            try
            {
                while (!done)
                {
                    // this is the line of code that receives the broadcase message. 
                    // It calls the receive function from the object listener (class UdpClient) 
                    // It passes to listener the end point groupEP. 
                    // It puts the data from the broadcast message into the byte array 
                    // named received_byte_array. 
                    // I don't know why this uses the class UdpClient and IPEndPoint like this. 
                    // Contrast this with the talker code. It does not pass by reference. 
                    // Note that this is a synchronous or blocking call. 
                    receive_byte_array = listener.Receive(ref groupEP);
                    received_data = Encoding.ASCII.GetString(receive_byte_array, 0, receive_byte_array.Length);
                    received_data = received_data.Substring(received_data.IndexOf('L') + 2);
                    received_data = received_data.Trim(new Char[] { '\0' }).Trim();
                    string[] dateAndEvent = received_data.Split(new string[] { ": " }, StringSplitOptions.RemoveEmptyEntries);
                    if (DateTime.TryParseExact(dateAndEvent[0], dateFormat, null, System.Globalization.DateTimeStyles.None, out parsedDate))
                    {
                        Console.WriteLine("Parsed the date: " + parsedDate.ToString());
                        //File.AppendAllText(logfile, "Parsed date: " + parsedDate.ToString() + "\tLog line: " + dateAndEvent[1] + Environment.NewLine);
                    }
                    else
                    {
                        Console.WriteLine("Failed to parse: " + dateAndEvent[0]);
                        //File.AppendAllText(logfile, "Failed to parse date from received data of: " + received_data + Environment.NewLine);
                        continue;
                    }

                    string serverIp = groupEP.ToString();
                    if (!parsers.ContainsKey(serverIp))
                    {
                        parsers.Add(serverIp, new LogLineParser(serverIp));
                        var serverQry = from s in context.Servers
                                        where s.ServerIP.Equals(serverIp)
                                        select s;
                        if (serverQry.FirstOrDefault() == null)
                        {
                            Server server = new Server();
                            server.ServerIP = serverIp;
                            context.Servers.AddObject(server);
                            context.SaveChanges();
                        }
                    }

                    try
                    {
                        parsers[serverIp].ParseLine(dateAndEvent[1], parsedDate);
                    }
                    catch (Exception ex)
                    {
                        Console.WriteLine(ex.ToString());
                        File.AppendAllText("parserexceptions.txt", "Exception: " + ex.ToString() + Environment.NewLine);
                        File.AppendAllText("parserexceptions.txt", "Stack trace: " + ex.StackTrace + Environment.NewLine);
                    }
                }
            }
            catch (Exception e)
            {
                Console.WriteLine(e.ToString());
                File.AppendAllText("exceptions.txt", "Exception: " + e.ToString() + Environment.NewLine);
                File.AppendAllText("exceptions.txt", "Inner exception: " + e.InnerException + Environment.NewLine);
                File.AppendAllText("exceptions.txt", "Stack trace: " + e.StackTrace + Environment.NewLine);
            }
            finally
            {
                listener.Close();
                context.Dispose();
                foreach (KeyValuePair<string, LogLineParser> kvp in parsers)
                {
                    kvp.Value.Dispose();
                }
            }
        }
    }
}